#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "parseFunction.h"

#define INT_TYPE 1
#define CHAR_TYPE 2
#define SHORT_TYPE 3
#define LONG_LONG_TYPE 4
#define POINTER_TYPE 5
#define UINT_TYPE 6
#define UCHAR_TYPE 7
#define USHORT_TYPE 8
#define ULONG_LONG_TYPE 9
#define VOID_TYPE 10
#define U_TYPE 11
#define LONG_TYPE 12
#define UNKNOWN_TYPE 0
#define TokenLeftBrace 0x100  // (
#define TokenRightBrace 0x101 // )
#define TokenComma 0x200      // ,


#define PARSE_END 0
#define PARSE_START 1
#define PARSE_RETURN_TYPE 2
#define PARSE_PARAM_START 3
#define PARSE_PARAM_TYPE 4

#define INT_TYPE_STR "int"
#define U_TYPE_STR "unsigned"
#define CHAR_TYPE_STR "char"
#define SHORT_TYPE_STR "short"
#define LONG_TYPE_STR "long"
#define VOID_TYPE_STR "void"

#define POINTER_TYPE_STR "void *"
#define LONG_LONG_TYPE_STR "long long"




typedef struct {
	const char * pos;
	char state;
	char currentType;
	char pre1Type;
	char pre2Type;
} ParseFuncState;



FunctionTypedef * newFunctionTypedef(void)
{
	FunctionTypedef * result = (FunctionTypedef *) malloc(sizeof(FunctionTypedef));
	result->returnType = UNKNOWN_TYPE;
	result->paramNum = 0;
	result->funcName = NULL;
	int i;
	for(i=0; i<16; i++)
	{
		result->paramType[i] = UNKNOWN_TYPE;
	}
	return result;
}

ParseFuncState * parseFunctionStart(const char *str)
{
	ParseFuncState * result = malloc(sizeof(ParseFuncState));
	result->pos = str;
	result->state = PARSE_START;
	result->currentType = UNKNOWN_TYPE;
	result->pre1Type = UNKNOWN_TYPE;
	result->pre2Type = UNKNOWN_TYPE;
	
	return result;
}

#define skipStartSpace(str) do{while(isspace(*str)){str++;}}while(0)
#define skipLeftBrace(str) do{while((*str != '(')&&(*str != '\0')){str++;} \
	if(*str == '('){str++;}}while(0)
#define skipComma(str) do{while((*str != ',')&&(*str != '\0')){}}while(0)
#define setParseStateType(parseState, wordType) do{parseState->pre2Type=parseState->pre1Type; \
	parseState->pre1Type=parseState->currentType; \
	parseState->currentType = wordType;}while(0)

const char *readWord(const char *str, char *word)
{
	const char * start = str;
	int i=0;
	skipStartSpace(start);
	while((isalnum(*start))||(*start == '_'))
	{
		word[i++] = *start++;
	}
	word[i] = '\0';
	return start;
}

int parseWordType(const char * word)
{
	if(strcmp(word, INT_TYPE_STR) == 0)
	{
		return INT_TYPE;
	}
	else if(strcmp(word, LONG_TYPE_STR) == 0)
	{
		return LONG_TYPE;
	}
	else if(strcmp(word, U_TYPE_STR) == 0)
	{
		return U_TYPE;
	}
	else if(strcmp(word, CHAR_TYPE_STR) == 0)
	{
		return CHAR_TYPE;
	}
	else if(strcmp(word, SHORT_TYPE_STR) == 0)
	{
		return SHORT_TYPE;
	}
	else if(strcmp(word, VOID_TYPE_STR) == 0)
	{
		return VOID_TYPE;
	}
	else
	{
		return UNKNOWN_TYPE;
	}
}

const char *typeToStr(int type)
{
	switch(type)
	{
	case INT_TYPE:
	case UINT_TYPE:
		return INT_TYPE_STR;
	case LONG_TYPE:
		return LONG_TYPE_STR;
	case CHAR_TYPE:
	case UCHAR_TYPE:
		return CHAR_TYPE_STR;
	case SHORT_TYPE:
	case USHORT_TYPE:
		return SHORT_TYPE_STR;
	case POINTER_TYPE:
		return POINTER_TYPE_STR;
	case VOID_TYPE:
		return VOID_TYPE_STR;
	default:
		return "";
	}
}

int parseCurrentType(ParseFuncState *parseState)
{
	if(parseState->currentType == POINTER_TYPE)
	{
		return POINTER_TYPE;
	}
	else if((parseState->currentType == INT_TYPE)||(parseState->currentType == LONG_TYPE))
	{
		if(parseState->pre1Type == LONG_TYPE)
		{
			if(parseState->pre2Type == U_TYPE)
			{
				return ULONG_LONG_TYPE;
			}
			else
			{
				return LONG_LONG_TYPE;
			}
		}
		else if(parseState->pre1Type == U_TYPE)
		{
			return UINT_TYPE;
		}
		else
		{
			return INT_TYPE;
		}
	}
	else if(parseState->currentType == CHAR_TYPE)
	{
		if(parseState->pre1Type == U_TYPE)
		{
			return UCHAR_TYPE;
		}
		else
		{
			return CHAR_TYPE;
		}
	}
	else if(parseState->currentType == SHORT_TYPE)
	{
		if(parseState->pre1Type == U_TYPE)
		{
			return USHORT_TYPE;
		}
		else
		{
			return SHORT_TYPE;
		}
	}
	else
	{
		return VOID_TYPE;
	}
}

int parseFunctionNext(FunctionTypedef * funcType, ParseFuncState *parseState)
{
	char word[128];
	int wordType;
	switch(parseState->state)
	{
	case PARSE_START:
		parseState->pos = readWord(parseState->pos, word);
		skipStartSpace(parseState->pos);
		
		
		
		
		
		if(*parseState->pos == '*')
		{
			wordType = parseWordType(word);
			setParseStateType(parseState, wordType);
			wordType = POINTER_TYPE;
			setParseStateType(parseState, wordType);	
			parseState->pos++;			
		}
		else if(*parseState->pos == '(')
		{
			parseState->state = PARSE_RETURN_TYPE;
			funcType->funcName = malloc(strlen(word)+1);
			strcpy(funcType->funcName, word);
		}
		else
		{
			wordType = parseWordType(word);
			setParseStateType(parseState, wordType);
		}
		break;
	case PARSE_RETURN_TYPE:
		funcType->returnType = parseCurrentType(parseState);
		skipLeftBrace(parseState->pos);
		parseState->state = PARSE_PARAM_START;
		parseState->pre1Type = UNKNOWN_TYPE;
		parseState->pre2Type = UNKNOWN_TYPE;
		parseState->currentType = UNKNOWN_TYPE;
		break;
	case PARSE_PARAM_START:
		parseState->pos = readWord(parseState->pos, word);
		
		skipStartSpace(parseState->pos);

		
		wordType = parseWordType(word);
		
		if(wordType != UNKNOWN_TYPE)
		{
			
			setParseStateType(parseState, wordType);
		}
		
		if(*parseState->pos == '*')
		{
			wordType = POINTER_TYPE;	
			setParseStateType(parseState, wordType);
			parseState->pos++;
		}
		else if((*parseState->pos == ',')||(*parseState->pos == ')'))
		{
			parseState->state = PARSE_PARAM_TYPE;
		}
		else
		{
			
		}
		break;
	case PARSE_PARAM_TYPE:
		funcType->paramType[funcType->paramNum++] = parseCurrentType(parseState);

		parseState->pre1Type = UNKNOWN_TYPE;
		parseState->pre2Type = UNKNOWN_TYPE;
		parseState->currentType = UNKNOWN_TYPE;

		if((*parseState->pos == ','))
		{
			
			parseState->state = PARSE_PARAM_START;	
			parseState->pos++;
			
		}
		else if((*parseState->pos == ')'))
		{
			parseState->state = PARSE_END;
		}
		else
		{
			
		}
		break;
	}
	return parseState->state;
}

FunctionTypedef * parseFunction(const char* str)
{
	FunctionTypedef * result = newFunctionTypedef();

	//printf("parseFunction: param num = %d, type = %d\n", result->paramNum, result->paramType[result->paramNum]);
	
	ParseFuncState *parseState = parseFunctionStart(str);
	
	while(parseFunctionNext(result, parseState) != PARSE_END){}	
	
	free(parseState);
	
	return result;
	
}
int getFunctionParamNumber(FunctionTypedef * func)
{
	return func->paramNum;
}

int getFunctionParamType(FunctionTypedef * func, int index)
{
	return func->paramType[index];
}

int getFunctionReturnType(FunctionTypedef * func)
{
	return func->returnType;
}

char *getFunctionName(FunctionTypedef * func)
{
	return func->funcName;
}

void freeFunctionTypedef(FunctionTypedef * func)
{
	if(func->funcName){ free(func->funcName); }
	free(func);
}

void toStrFunctionTypedef(FunctionTypedef * func, char *buf)
{
	int len, i;
	sprintf(buf, "%s %s(", typeToStr(func->returnType), func->funcName);
	for(i=0; i<func->paramNum; i++)
	{
		len = strlen(buf);
		if(i == func->paramNum-1)
		{
			sprintf(&buf[len], "%s", typeToStr(func->paramType[i]));
		}
		else
		{
			sprintf(&buf[len], "%s,", typeToStr(func->paramType[i]));
		}
	}
	if(func->paramNum == 0)
	{
		len = strlen(buf);
		sprintf(&buf[len], "%s", VOID_TYPE_STR);
	}
	len = strlen(buf);
	sprintf(&buf[len], ")");
	
}

#if 0
void testParseFunction(void)
{
	FunctionTypedef *funcType = parseFunction("int quit_cb(void)");
	printf("return type = %d\n", getFunctionReturnType(funcType));
	printf("func name = %s\n", getFunctionName(funcType));
	int n = getFunctionParamNumber(funcType);
	printf("param num = %d\n", n);
	int i;
	for(i=0; i<n; i++)
	{
		printf("param %d type = %d\n", i, getFunctionParamType(funcType, i));
	}
	char buf[128];
	toStrFunctionTypedef(funcType, buf);
	printf("%s\n", buf);
	
}

int main(void)
{
	testParseFunction();
	return 0;
}
#endif
